package wsresource.server;

import java.sql.SQLException;
import javax.transaction.Status;

import javax.jws.WebMethod;
import javax.jws.WebService;

@WebService
public class WSResourceManager {

  /**
   * Commits the work of the global transaction specified by xid.
   * @param xid
   * @param onePhase
   */
  @WebMethod
  public boolean commit(String xid, boolean onePhase) {
    Context ctx = ResourceManager.getInstance().getContextByXID(xid);
    if(ctx.toRollback == true){
      return false;
    }
    if (onePhase) {
      if (commitOnePhase(xid)) {
        //TODO: Desasociar el recurso de la transaccion after commit
        ctx.status = Status.STATUS_NO_TRANSACTION; 
        return true;
      }
    } else {
      if (commitPrepared(xid)) {
        //TODO: Desasociar el recurso de la transaccion after commit
        ctx.status = Status.STATUS_NO_TRANSACTION; 
        try {
          ctx.conn.setAutoCommit(ctx.localAutoCommitMode);
        } catch (SQLException ex) {
          System.err.println("Error: " + ex.getMessage());
        }
        return true;
      }
    }
    return false;
  }
  /**
   * Commit the work when only one resource is enroled
   * @param xid
   * @return true if the work was completed, false if not
   */
  private boolean commitOnePhase(String xid) {
    Context ctx = ResourceManager.getInstance().getContextByXID(xid);
    ctx.status = Status.STATUS_COMMITTING;
    try {
      System.out.println("Commit one phase " + xid);
      ctx.conn.commit();
      System.out.println("Do the Commit one phase " );
    } catch (SQLException ex) {
      System.err.println("Error: " + ex.getMessage());
      return false;
    }
    return true;
  }
  
  /**
   * Commit the work that was prepared in the two phase commit
   * @param xid
   *  @return true if the work was completed, false if not
   */
  private boolean commitPrepared(String xid) {
    Context ctx = ResourceManager.getInstance().getContextByXID(xid);
    ctx.status = Status.STATUS_COMMITTING;
    try {
      ctx.localAutoCommitMode = ctx.conn.getAutoCommit();
      System.out.println("Execute statment COMMIT PREPARED '" + xid
          +"-"+ ctx.id+"';");
      ctx.conn.createStatement().executeUpdate(
          "COMMIT PREPARED '" + xid +"-"+ctx.id+ "';");
    } catch (SQLException e) {
      System.err.println("Error: " + e.getMessage());
      return false;
    }
    return true;
  }
  
  /**
   * Disassociates the resource from the transaction branch 
   * specified in xid.
   * @param xid
   * @param flags
   */
  @WebMethod
  public void end(String xid, int flags) {
    Context ctx = ResourceManager.getInstance().getContextByXID(xid);
    ctx.status = Status.STATUS_NO_TRANSACTION;
  }

  /**
   * Ask the resource to prepare for a commit of the global 
   * transaction specified in xid.
   * @param xid
   */
  @WebMethod
  public int prepare(String xid) {
    Context ctx = ResourceManager.getInstance().getContextByXID(xid);
    System.out.println("Enter to Prepare");
    ctx.status = Status.STATUS_PREPARING;
    // No previous errosr
    if (!ctx.toRollback) {
      try {
        System.out.println("Execute statment PREPARE TRANSACTION '"
            + xid +"-"+ctx.id+ "';");
        ctx.conn.createStatement().executeUpdate(
            "PREPARE TRANSACTION '" + xid +"-"+ctx.id+ "';");
      } catch (SQLException e) {
        System.err.println("Error: " + e.getMessage());
        System.out.println("Vote rollback");
        return 1; // Vote rollback
      }
      try {
        ctx.conn.setAutoCommit(ctx.localAutoCommitMode);
      } catch (SQLException e) {
        System.err.println("Error: " + e.getMessage());
      }
      ctx.status = Status.STATUS_PREPARED;
      System.out.println("Vote commit");
      return 0; // Vote commit
    } else {
      System.out.println("Vote rollback");
      return 1; // Vote rollback
    }
  }

  /**
   * Informs the resource manager to rollback work done on
   * behalf of a transaction specified in xid.
   * @param xid
   */
  @WebMethod
  public boolean rollback(String xid) {
    Context ctx = ResourceManager.getInstance().getContextByXID(xid);
    try {
      if (ctx.status == Status.STATUS_PREPARED) {
        System.out.println("Execute statment ROLLBACK PREPARED '" + xid
            +"-"+ctx.id+ "';");
        ctx.conn.createStatement().executeUpdate(
            "ROLLBACK PREPARED '" + xid +"-"+ctx.id+ "';");
      } else {
        System.out.println("Execute ROLLBACK '" + xid + "-"+ctx.id+"';");
        ctx.conn.setAutoCommit(false);
        ctx.conn.rollback();
        ctx.conn.setAutoCommit(ctx.localAutoCommitMode);
      }
    } catch (SQLException e) {
      System.err.println("Error: " + e.getMessage());
      return false;
    }
    //TODO: Desasociar el recurso de la transaccion after rollback
    return true;
  }

  /**
   * Asociates the resource with the transaction specified in xid 
   * @param xid
   * @param flags
   */
  @WebMethod
  public void start(String xid, int flags) {
    ResourceManager.getInstance().createContextByXID(xid);
  }
}
